package com.sprouting.ops.utils;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.sprouting.ops.interfaces.ConstantBase;
import com.sprouting.ops.interfaces.TypeFunction;
import com.sprouting.ops.model.BaseModel;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 实体工具类
 *
 * @author ：LX（长沙麓谷）
 * @date 创建时间： 2022/7/29 0:04
 */
public class EntityTool {


    /**
     * 通过对象获取属性名称
     * 使用示例和效果： 比如 ObjTool.getFieldName(User::getId)  返回得到 id 这个属性。注意，返回的不是值，而是key
     *
     * @param name 要获取的名称
     * @return 返回名称
     * @param <T>
     * @param <R>
     */
    public static <T, R> String getFieldName(TypeFunction<T, R> name){
        return TypeFunction.getLambdaColumnName(name);
    }


    /**
     * 保存时自动将继承 BaseModel 的基础数据部分填充完成
     * @param obj 要填充的对象，必须继承自 BaseModel
     * @param <T> 继承自 BaseModel 的对象
     * @return 最终返回继承对象
     */
    public static  <T extends BaseModel> T saveBase(T obj){
        Date now = new Date();
        obj.setCreateId(StpUtil.getLoginIdAsString());
        obj.setUpdateId(StpUtil.getLoginIdAsString());
        obj.setDelType(ConstantBase.DelType.ADD);
        obj.setCreateTime(now);
        obj.setUpdateTime(now);
        return obj;
    }

    /**
     * 修改时自动将继承 BaseModel 的基础数据部分填充完成
     * @param obj 要填充的对象，必须继承自 BaseModel
     * @param <T> 继承自 BaseModel 的对象
     * @return 最终返回继承对象
     */
    public static  <T extends BaseModel> T updBase(T obj){
        Date now = new Date();
        obj.setUpdateId(StpUtil.getLoginIdAsString());
        obj.setUpdateTime(now);
        obj.setCreateId(null);
        obj.setCreateTime(null);
        return obj;
    }

    /**
     * 删除时自动将继承 BaseModel 的基础数据部分填充完成
     * @param obj 要填充的对象，必须继承自 BaseModel
     * @param <T> 继承自 BaseModel 的对象
     * @return 最终返回继承对象
     */
    // public static  <T extends BaseModel> T delBase(T obj){
    //     Date now = new Date();
    //     obj.setUpdateId(StpUtil.getLoginIdAsString());
    //     obj.setUpdateTime(now);
    //     obj.setDelType(ConstantBase.DelType.DEL);
    //     return obj;
    // }

    /**
     * list 转 map
     * 代替的写法
     *         Map<String, OpsComponent> componentMap = new HashMap<>();
     *         if (CollUtil.isNotEmpty(componentList)){
     *             componentMap = componentList.stream().collect(Collectors.toMap(OpsComponent::getId, Function.identity(), (o, n) -> n));
     *         }
     *  使用：Map<String, OpsApp> appMap = toMap(appList, OpsApp::getId);
     * @param list 要转换的对象
     * @param keyMapper 要转的对象，可以函数式写法，比如 Component::getId
     * @return 当为空的时候返回一个hashmap对象，否则返回转换后的map
     * @param <T>
     * @param <K>
     */
    public static <T, K> Map<K, T> toMap(List<T> list, Function<T, K> keyMapper) {
        return CollUtil.isEmpty(list)
                ? new HashMap<>()
                : list.stream().collect(Collectors.toMap(keyMapper, Function.identity(), (o, n) -> n));
    }

    /**
     * List转分组Map（替代Collectors.groupingBy）
     * 替代写法：
     *      List<BaseDockerImagePort> portList = 查询出结果集;
     *      if (portList != null && portList.size > 0){
     *          Map<String, List<BaseDockerImagePort>> map = portList.stream().collect(Collectors.groupingBy(BaseDockerImagePort::getTfBaseDockerImageId));
     *      }
     * 使用：Map<String, List<BaseDockerImagePort>> mapPort = EntityTool.groupToMap(portList, BaseDockerImagePort::getTfBaseDockerImageId);
     *
     * @param list 源集合
     * @param classifier 分组依据函数
     * @return 非空Map（空集合返回空HashMap）
     */
    public static <T, K> Map<K, List<T>> groupToMap(List<T> list, Function<T, K> classifier) {
        return CollUtil.isEmpty(list)
                ? new HashMap<>()
                : list.stream().collect(Collectors.groupingBy(classifier));
    }

    /**
     * 从记录集合中提取非空字段值并添加到目标集合
     * 调用：addNonEmptyFieldValues(records, OpsStakeholderVo::getProjectRole, dictIdList);
     * 代替的方法：
             List<String> dictIdList = new ArrayList<>();
             List<String> levelList = records.stream().filter(obj -> StrUtil.isNotEmpty(obj.getLevel())).map(OpsStakeholderVo::getLevel).collect(Collectors.toList());
             if (CollUtil.isNotEmpty(levelList)){
                dictIdList.addAll(levelList);
             }
     * @param records 源记录集合
     * @param fieldGetter 字段获取函数
     * @param targetList 目标集合
     * @param <T> 记录类型
     */
    public static <T> void addNonEmptyFieldValues(List<T> records, Function<T, String> fieldGetter, List<String> targetList) {
        List<String> fieldValues = records.stream()
                .filter(obj -> StrUtil.isNotEmpty(fieldGetter.apply(obj)))
                .map(fieldGetter)
                .distinct()
                .collect(Collectors.toList());

        if (CollUtil.isNotEmpty(fieldValues)) {
            targetList.addAll(fieldValues);
        }
    }
}
